﻿// owner 蒋家伟

#include "Document.h"

// std
#include <fstream>
#include <sstream>

// rapidjson
#include "rapidjson/writer.h"

// jsdk
#include "JsonUtils.h"
#include "DBSchemaObject.h"
#include "ElementNotifyUtils.h"
#include "ObjectReflectDefine.h"
#include "CommonFieldDescriptor.h"
#include "IDocumentChangedEvent.h"
#include "IElementBasicInfomation.h"
#include "DocumentChangedEventArgs.h"
#include "Dbg_Warn_Define.h"

using namespace jsdk;

namespace
{
    // 将jsonDoc写入
    bool save(const JsonDocument& jsonDoc, const std::wstring& path)
    {
        rapidjson::StringBuffer buffer;
        rapidjson::Writer<rapidjson::StringBuffer> write(buffer);
        jsonDoc.Accept(write);

        std::ofstream os(path);
        if (!os.is_open())
        {
            return false;
        }

        os << buffer.GetString();
        os.close();

        return true;
    }

    // 将jsonDoc读取
    bool load(const std::wstring& loadPath, JsonDocument& jsonDoc)
    {
        std::ifstream is(loadPath);
        if (!is.is_open())
        {
            return false;
        }

        std::stringstream buffer;
        buffer << is.rdbuf();
        std::string jsonContent(buffer.str());

        return !jsonDoc.Parse(jsonContent.c_str(), jsonContent.size()).HasParseError();
    }
}

jsdk::OwnerPtr<jsdk::Document> jsdk::Document::create(const std::wstring& loadPath)
{
    JsonDocument doc;
    // 1、读取JsonDocument
    bool success = ::load(loadPath, doc);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(success && doc.IsObject(), L"序列化的json文件打开失败", L"蒋家伟", L"2023-12-19");

    IDocumentChangedEvent* pDocumentChangedEvent = IDocumentChangedEvent::get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDocumentChangedEvent, L"文档事件未初始化", L"蒋家伟", L"2023-12-19");

    jsdk::OwnerPtr<jsdk::Document> opDoc = NEW_AS_OWNERPTR(Document);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opDoc, L"文档对象创建失败", L"蒋家伟", L"2023-12-19");

    // 2、序列化前事件发送
    {
        DocumentChangedEventArgs args(opDoc.get(), jsdk::DocumentChangedType::BeforeUnserialize);
        pDocumentChangedEvent->sendEvent(&args);
    }

    // 3、序列化开始，并插入文档
    for (auto iter = doc.MemberBegin(); iter != doc.MemberEnd(); ++iter)
    {
        const JsonValue& jsonObjectValue = iter->value;
        DBG_WARN_AND_CONTINUE_UNLESS(jsonObjectValue.IsObject(), L"文档存储应该全是obejct", L"蒋家伟", L"2023-12-19");
        jsdk::UniqueId typeUid;
        success = CommonFieldDescriptor::getClassUidFromJsonObject(jsonObjectValue, typeUid);
        DBG_WARN_AND_CONTINUE_UNLESS(success, L"缺少类别描述", L"蒋家伟", L"2023-12-19");
        OwnerPtr<DBSchemaObject> opDBSchemaObject = ObjectReflectUtils::getObjectReflectImp(typeUid, nullptr);
        DBG_WARN_AND_CONTINUE_UNLESS(opDBSchemaObject, L"反射对象失败，类别为" + typeUid.toString(), L"蒋家伟", L"2023-12-19");
        const JsonValue* pJsonSourceValue = JsonUtils::getJsonValue(jsonObjectValue, CommonFieldDescriptor::s_pValue_Key);
        DBG_WARN_AND_CONTINUE_UNLESS(pJsonSourceValue, L"获取值失败，类别为" + typeUid.toString(), L"蒋家伟", L"2023-12-19");
        success = opDBSchemaObject->unserialize(*pJsonSourceValue);
        DBG_WARN_AND_CONTINUE_UNLESS(success, L"反流失败", L"蒋家伟", L"2023-12-19");
        OwnerPtr<IElement> opElement = transformOwnerShipAndCast<IElement>(opDBSchemaObject);
        DBG_WARN_AND_CONTINUE_UNLESS(opElement, L"反流对象不是Element", L"蒋家伟", L"2023-12-19");
        const JsonValue& jsonObjectName = iter->name;
        DBG_WARN_AND_CONTINUE_UNLESS(jsonObjectName.IsInt64(), L"存储的ID应该是int64", L"蒋家伟", L"2023-12-19");
        ElementId elementId(jsonObjectName.GetInt64());
        bool success = opDoc->insertElement(elementId, transformOwnerShip(opElement));
        DBG_WARN_AND_CONTINUE_UNLESS(success, L"插入对象失败，其ID为:" + StringUtils::toWString(elementId.toValue()), L"蒋家伟", L"2023-12-19");
    }

    // 4、序列后，事件发送
    {
        DocumentChangedEventArgs args(opDoc.get(), jsdk::DocumentChangedType::AfterUnserialize);
        pDocumentChangedEvent->sendEvent(&args);
    }

    return transformOwnerShip(opDoc);
}

jsdk::OwnerPtr<jsdk::Document> jsdk::Document::createEmpty()
{
    return NEW_AS_OWNERPTR(Document);
}

bool jsdk::Document::save(const std::wstring& savePath) const
{
    // 1、将文档所有数据写入jsonDoc
    JsonDocument jsonDoc;
    jsonDoc.SetObject();
    for (const auto& iter : m_elementToElementUMap)
    {
        // 1.1、临时对象不写入
        DBG_WARN_AND_CONTINUE_UNLESS(iter.second, L"存储了一个空对象其Id : " + StringUtils::toWString(iter.first.toValue()) , L"蒋家伟", L"2023-12-18");
        const IElementBasicInfomation* pBasicInfo = iter.second->getBasicInfomation();
        DBG_WARN_AND_CONTINUE_UNLESS(pBasicInfo, L"缺少BasicInfo其Id : " + StringUtils::toWString(iter.first.toValue()), L"蒋家伟", L"2023-12-18");
        if(pBasicInfo->isTemporaryObject()) continue;

        // 1.2、写入所有的普通对象
        const DBSchemaObject* pDbShemaObject = quick_cast<DBSchemaObject>(iter.second.get());
        DBG_WARN_AND_CONTINUE_UNLESS(pDbShemaObject, L"当前对象是不是shema对象，请查看对象", L"蒋家伟", L"2023-12-18");

        JsonObject object = JsonUtils::createObject();
        DBG_WARN_AND_CONTINUE_UNLESS(pDbShemaObject->serialize(jsonDoc, object), pDbShemaObject->getClassName() + L"流化失败", L"蒋家伟", L"2023-12-07");
        JsonValue elementIdValue;
        elementIdValue.SetInt64(iter.first.toValue());
        JsonUtils::insert(jsonDoc, jsonDoc, std::move(elementIdValue), std::move(object));
    }

    // 2、写入
    return ::save(jsonDoc, savePath);
}

bool jsdk::Document::AddElement(OwnerPtr<IElement> opElement)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(opElement, L"传入一个空的element对象", L"蒋家伟", L"2023-12-18");
    const IElementBasicInfomation* pBasicInfo = opElement->getBasicInfomation();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pBasicInfo, L"当前对象没有基本信息", L"蒋家伟", L"2023-12-18");

    // 1、根据当前对象是否为临时对象，确定ElementId
    ElementId elementId = ElementId::s_InvalidId;
    {
        if (pBasicInfo->isTemporaryObject())
        {
            elementId = m_idGenerator.getCommonValidId();
        }
        else
        {
            elementId = m_idGenerator.getTempValidId();
        }
    }

    // 2、将对象写入文档
    DBG_WARN_AND_RETURN_FALSE_UNLESS(elementId.isValid(), L"id创建失败，对象已经超过创建的最大数量", L"蒋家伟", L"2023-12-18");
    IElement* pElement = opElement.get();
    bool success = this->insertElement(elementId, transformOwnerShip(opElement));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(success, StringUtils::toWString(elementId.toValue()) + L"插入对象失败", L"蒋家伟", L"2023-12-18");

    // 3、发出添加Element事件
    ElementNotifyUtils::ElementDataChangedNotify(pElement, ElementChangedType::AddElement);
    return true;
}

void jsdk::Document::setRunTimeId(RunTimeId runtimeId)
{
    m_runTimeId = runtimeId;
}

bool jsdk::Document::insertElement(const jsdk::ElementId& elementId, OwnerPtr<IElement> opElement)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(elementId.isValid(), L"传递一个非法的ElementId", L"蒋家伟", L"2023-12-18");
    DBG_WARN_AND_RETURN_FALSE_UNLESS(opElement, L"向文档中插入一个空对象其ID" + StringUtils::toWString(elementId.toValue()), L"蒋家伟", L"2023-12-18");

    const IElementBasicInfomation* pBasicInfo = opElement->getBasicInfomation();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pBasicInfo, L"当前对象没有基本信息", L"蒋家伟", L"2023-12-18");
    IElement* pElement = opElement.get();

    if (m_elementToElementUMap.insert(std::make_pair(elementId, transformOwnerShip(opElement))).second)
    {
        {
            // 1、插入成功后，更新Element的关系
            pElement->setElementId(elementId);
            pElement->setDocument(this);
            // 2、更新所有组件的对象所属关系，至此Element对象完全设置成功
            pElement->setComponentOwnerElement();
        }

        {
            // 3、当前所有数据更新成功后，更新ID生成器, 保证ID的非重复性
            if (pBasicInfo->isTemporaryObject())
            {
                m_idGenerator.UpdateCommonId(elementId);
            }
            else
            {
                m_idGenerator.UpdateCommonId(elementId);
            }
        }

        return true;
    }
    return false;
}

jsdk::IElement* jsdk::Document::getElement(const ElementId& elementId)
{
    auto iter = m_elementToElementUMap.find(elementId);
    if (iter != m_elementToElementUMap.end())
    {
        return iter->second.get();
    }
    return nullptr;
}

std::set<jsdk::ElementId> jsdk::Document::getAllElementId() const
{
    std::set<jsdk::ElementId> res;
    for (const auto& pair : m_elementToElementUMap)
    {
        res.insert(pair.first);
    }
    return res;
}

bool jsdk::Document::deleteElement(const ElementId& elementId)
{
    // todo 先简单实现
    const auto& iter = m_elementToElementUMap.find(elementId);
    if (iter != m_elementToElementUMap.end())
    {
        m_elementToElementUMap.erase(iter);
        ElementNotifyUtils::ElementDataChangedNotify(this, jsdk::ChangedStatusUMap{ std::make_pair(elementId, ElementChangedType::DeleteElement) });
        return true;
    }

    return false;
}

bool jsdk::Document::deleteElements(const std::set<ElementId>& elementIds, std::set<ElementId>* pDeleteFailElementId)
{
    ChangedStatusUMap deleteSuccessUMap;

    // todo 先简单实现
    for (const auto& elementId : elementIds)
    {
        const auto& iter = m_elementToElementUMap.find(elementId);
        if (iter != m_elementToElementUMap.end())
        {
            m_elementToElementUMap.erase(iter);
            deleteSuccessUMap.insert(std::make_pair(elementId, ElementChangedType::DeleteElement));
        }
        else
        {
            if (pDeleteFailElementId)
            {
                pDeleteFailElementId->insert(elementId);
            }
        }
    }

    // 删除完毕后
    if (!deleteSuccessUMap.empty())
    {
        ElementNotifyUtils::ElementDataChangedNotify(this, std::move(deleteSuccessUMap));
    }
    return deleteSuccessUMap.size() == elementIds.size();
}

const jsdk::IElement* jsdk::Document::getElement(const ElementId& elementId) const
{
    auto iter = m_elementToElementUMap.find(elementId);
    if (iter != m_elementToElementUMap.end())
    {
        return iter->second.get();
    }
    return nullptr;
}

jsdk::IDocument::RunTimeId jsdk::Document::getRunTimeId() const
{
    return m_runTimeId;
}

